﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;

namespace ValidationFramework.Utilities
{
	public static class ExprUtil
	{
#if (!WindowsCE)
		/// <summary>
		/// Get the name of a member from an <see cref="Expression{TDelegate}"/>.
		/// </summary>
		/// <typeparam name="TMember">The <see cref="Type"/> of the member.</typeparam>
		/// <param name="expression">The lambda <see cref="Expression{TDelegate}"/> representing the member.</param>
		/// <returns>The name of the member.</returns>
		/// <exception cref="ArgumentNullException"><paramref name="expression"/> is a null reference.</exception>
		public static string GetMemberName<TMember>(Expression<Func<TMember>> expression)
		{
			Guard.ArgumentNotNull(expression, "expression");
			return (((MemberExpression)expression.Body).Member).Name;
		}


		public static string GetMemberNameFromExpression<TDeclaringType>(Expression<Func<TDeclaringType, object>> expression)
		{
			Guard.ArgumentNotNull(expression, "expression");

			LambdaExpression lambda = expression as LambdaExpression;
			if (lambda == null) throw new ArgumentException("Not a lambda expression", "member");

			MemberExpression memberExpr = null;

			// The Func<TTarget, object> we use returns an object, so first statement can be either 
			// a cast (if the field/property does not return an object) or the direct member access.
			if (lambda.Body.NodeType == ExpressionType.Convert)
			{
				// The cast is an unary expression, where the operand is the 
				// actual member access expression.
				memberExpr = ((UnaryExpression)lambda.Body).Operand as MemberExpression;
			}
			else if (lambda.Body.NodeType == ExpressionType.MemberAccess)
			{
				memberExpr = lambda.Body as MemberExpression;
			}

			if (memberExpr == null) throw new ArgumentException("Not a member access", "member");

			return memberExpr.Member.Name;
		}
#endif
	}
}
